package com.qf.microuser.user.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qf.common.core.constants.AliyunOSSConstants;
import com.qf.common.core.entity.User;
import com.qf.common.core.enums.RedisKeyEnum;
import com.qf.common.core.enums.SmsEnum;
import com.qf.common.core.util.JwtUtils;
import com.qf.common.minio.utils.MinioUtil;
import com.qf.common.neo4j.node.UserNode;
import com.qf.common.neo4j.utils.Neo4jUtils;
import com.qf.common.redis.utils.RedisUtil;
import com.qf.common.sms.utils.AliSmsUtils;
import com.qf.microuser.user.mapper.UserMapper;
import com.qf.microuser.user.param.LoginParam;
import com.qf.microuser.user.param.RegisterParam;
import com.qf.microuser.user.service.UserService;
import com.qf.microuser.user.vo.UserInfoVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 天--道--酬--勤
 *
 * @author LiangGaoQiang
 * @ClassName UserServiceImpl
 * @Date: 2025/5/21 16:37
 * @Description: 描述
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private Neo4jUtils neo4jUtils;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private MinioUtil minioUtil;


    @Override
    public void register(RegisterParam param) {
        // 用户名或者手机号是否唯一
        User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, param.getUsername()));
        if (user1 != null) {
            throw new RuntimeException("用户名已存在!");
        }

        // 判断邀请码是否有效
        Long count = userMapper.selectCount(Wrappers.lambdaQuery(User.class).eq(User::getInviteCode, param.getInviteCode()));
        if (count <= 0) {
            throw new RuntimeException("邀请码错误!");
        }

        User user = new User();
        // 借助hutool工具随机生成6为的字符串作为邀请码
        BeanUtils.copyProperties(param, user);
        String inviteCode = RandomUtil.randomString(6);
        // 判断邀请码是否重复
        Long count2 = userMapper.selectCount(Wrappers.lambdaQuery(User.class).eq(User::getInviteCode, inviteCode));
        if (count2 > 0) {
            throw new RuntimeException("邀请码重复!");
        }


        // todo:验证码的判断，即验证码是否过期

        user.setInviteCode(inviteCode);
        userMapper.insert(user);

        // 注册成功后，将用户节点添加到图数据库neo4j中
        // UserNode pnode = neo4jUtils.getUserNode()
        // if (pnode == null){
        //
        // }


    }

    @Override
    public String login(LoginParam loginParam) {
        // 根据用户名查询用户
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginParam.getUsername()));

        // 认证和授权
        if (user == null) {
            throw new RuntimeException("用户名不存在!");
        }
        // 这里假设密码是明文存储和比较的，实际开发中应使用加密存储和比较
        if (!user.getPassword().equals(loginParam.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // 使用JwtToken生成token
        Map<String, Object> map = new HashMap<>();
        map.put("uid", user.getId());
        // 生成jwt表示的token
        return JwtUtils.createJwt(map);
    }

    @Override
    public UserInfoVO getUserInfo(Integer uid) {
        User user = userMapper.selectById(uid);
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);

        // 这里需要判断一下用户的头像是否是默认的，如果是默认的，则设置成默认的图片
        String defaultAvatar = "https://img2.baidu.com/it/u=3846307121,3270602211&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500";
        if (!userInfoVO.getAvatar().equals(defaultAvatar)) {
            userInfoVO.setAvatar(AliyunOSSConstants.PUBLIC_URL + userInfoVO.getAvatar());
        }


        // 对于一些属性需要单独处理一下
        userInfoVO.setSignFlag(0);
        userInfoVO.setBalance(10000.0);
        userInfoVO.setPoint(100);
        return userInfoVO;
    }

    /**
     * 查询所有父级用户 (不包括当前用户)，我是用的是递归循环查询，但递归查询会消耗性能，
     * 由于 MySQL 5.7 不支持递归查询，此方法会进行 N 次数据库查询（N 为层级深度），适合以下场景：
     * 数据量较小（如最多几十层）
     * 非高频访问接口
     * 可配合缓存（如 Redis）减少数据库压力
     *
     * @param userId 用户ID
     * @return 所有父级用户
     */
    @Override
    public List<User> findAllParentUsers(Integer userId) {
        List<User> result = new ArrayList<>();
        // 查询当前用户的父级用户的ID
        Integer currentParentId = userMapper.selectById(userId).getPid();
        // 循环查询父级用户
        while (currentParentId != null) {
            User user2 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, currentParentId));
            if (user2 == null) break;

            if (currentParentId.equals(0)) break; // 跳出循环，防止死循环

            result.add(user2);
            currentParentId = user2.getPid(); // 下一个父用户ID
        }

        return result;
    }

    @Override
    public boolean updateUserInfoById(User user) {
        // 更新用户信息
        return userMapper.updateById(user) > 0;
    }

    @Override
    public UserNode getUserNodeinvite(Integer userId) {
        // return userMapper.;
        return null;
    }

    @Override
    public void getPhoneVerifyCode(String phone) {
        // 验证手机号是否合法

        // 生成验证码--使用hutool工具生成随机6位数字
        String code = RandomUtil.randomNumbers(6);
        // 保存验证码到redis或其他缓存中
        String key = String.format(RedisKeyEnum.KEY_CODE.getKey(), phone);
        redisUtil.setCacheObject(key, code, RedisKeyEnum.KEY_CODE.getExpireTime(), TimeUnit.SECONDS);
        // 签名、模版ID、手机号、验证码
        AliSmsUtils.sendSms(SmsEnum.SMS_CODE.getSignName(), SmsEnum.SMS_CODE.getTemplateCode(), phone, code);

    }

    @Override
    public String uploadAvatar(MultipartFile file) {
        String filename = file.getOriginalFilename();

        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + filename.substring(filename.lastIndexOf("."));

        // 这里需要先判断一下文件是否上传成功，如果上传成功，则返回minio的路径，如果上传失败，则抛出异常

        try {
            return minioUtil.upload(filename, file.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
